//
//  YSGScrollView.swift
//  EyeVisionForDoctors
//
//  Created by PMC on 2020/11/20.
//  Copyright © 2020 tao Tao. All rights reserved.
//

import UIKit

typealias TapCallback = (UIImageView) -> Void

class YSGScrollView: UIScrollView {

    var tapCallback: TapCallback?
    
    var imageView: UIImageView!
    var tapImageView: UIImageView!
    
    fileprivate var isTapTouch = false
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        makeUI()
        
//        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: , object: <#T##Any?#>)
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        makeUI()
    }
    
    private func makeUI() {
        imageView = UIImageView(frame: frame)
        imageView.isUserInteractionEnabled = true
        imageView.contentMode = .scaleAspectFit
        addSubview(imageView)
        
        isScrollEnabled = false
        minimumZoomScale = 1.0
        maximumZoomScale = 3.0
        backgroundColor = .clear
        showsVerticalScrollIndicator = false
        showsHorizontalScrollIndicator = false
        delegate = self
        contentSize = CGSize(width: screenW, height: 0)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = (touches as NSSet).anyObject() as? UITouch else { return }
        
        if touch.tapCount == 1 {
            perform(#selector(tapHandler(_:)), with: nil, afterDelay: 0.2)
        } else {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(tapHandler), object: nil)
            if !isTapTouch {
                doubleHandler(touch)
            }
        }
    }
}

// MARK: - private funcs
private extension YSGScrollView {
    func convertRect(for view: UIView?) -> CGRect {
        let rootView = UIApplication.shared.keyWindow?.rootViewController?.view
        if let view = view, let superview = view.superview {
            let rect = superview.convert(view.frame, to: rootView)
            return rect
        }
        return .zero
    }
    
    func zoomRect(for scale: CGFloat, center: CGPoint) -> CGRect {
        let width = screenW / scale
        let height = screenH / scale
        let pointX = center.x - (width / 2)
        let pointY = center.y - (height / 2)
        return CGRect(x: pointX, y: pointY, width: width, height: height)
    }
    
    func reset() {
        zoomScale = 1.0
        imageView.frame = imageView.bounds
    }
    
    func frameLogic() -> CGRect {
        let imageWidth = self.tapImageView.image?.size.width ?? 0
        let imageHeight = self.tapImageView.image?.size.height ?? 0
        var width: CGFloat = 1.0
        var height: CGFloat = 1.0
        var scale: CGFloat = 1.0
        if screenW > screenH && imageHeight != 0 { // 以高度为基准, 等比例宽度
            scale = screenH / imageHeight
        } else if imageWidth != 0 { // 以宽度为基准, 等比例高度
            scale = screenW / imageWidth
        }
        width = scale * imageWidth
        height = scale * imageHeight
        return CGRect(x: 0, y: 0, width: width, height: height)
    }
    
    func animationOfOpacityAndScale() {
        let duration: CFTimeInterval = 0.3
        let opacityAnim = CABasicAnimation(keyPath: "opacity")
        opacityAnim.fromValue = 1.0
        opacityAnim.toValue = 0.0
        opacityAnim.duration = duration
        opacityAnim.isRemovedOnCompletion = false
        opacityAnim.fillMode = .forwards
        
        let scaleAnim = CABasicAnimation(keyPath: "transform.scale")
        scaleAnim.fromValue = zoomScale
        scaleAnim.toValue = 3.5
        scaleAnim.duration = duration
        scaleAnim.delegate = self
        scaleAnim.isRemovedOnCompletion = false
        scaleAnim.fillMode = .forwards
        
        imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        superview?.superview?.superview?.superview?.layer.add(opacityAnim, forKey: "opacity")
        imageView.layer.add(scaleAnim, forKey: "scale")
    }
    
    @objc func tapHandler(_ touch: UITouch) {
        isTapTouch = true
        isUserInteractionEnabled = false
        bounds = CGRect(x: 0, y: 0, width: screenW, height: screenH)
        guard tapImageView.superview != nil else { // tapImageView.superview没有渲染出来
            animationOfOpacityAndScale()
            return
        }
        
        let frame = convertRect(for: tapImageView)
        guard frame.origin.x > 0 && frame.origin.x < screenW &&
            frame.origin.y > 0 && frame.origin.y < screenH else {
            animationOfOpacityAndScale()
            return
        }
        
        var duration = 0.0
        if screenW > screenH {
            duration = Double(0.20 / screenH * imageView.frame.size.height)
        } else {
            duration = Double(0.20 / screenW * imageView.frame.size.width)
        }
        superview?.superview?.superview?.superview?.backgroundColor = .clear
        UIView.animate(withDuration: TimeInterval(duration), delay: 0, options: .curveLinear, animations: {
            self.imageView.frame = frame
        }) { _ in
            self.tapCallback?(self.imageView)
        }
    }
    
    func doubleHandler(_ sender: UITouch) {
        var zoomScale = self.zoomScale
        let minimumZoomScale: CGFloat = 1.0
        let maximumZoomScale: CGFloat = 2.0
        zoomScale = (zoomScale == minimumZoomScale) ? maximumZoomScale : minimumZoomScale
        let zoomRect = self.zoomRect(for: zoomScale, center: sender.location(in: sender.view))
        isTapTouch = false
        zoom(to: zoomRect, animated: true)
    }
}

// MARK: - public funcs
extension YSGScrollView {
    func setImageViewFrame() {
        zoomScale = minimumZoomScale
        imageView.frame = frameLogic()
        imageView.center = center
    }
    
    func doAnimation(on imageView: UIImageView?) {
        tapImageView = imageView
        self.imageView.frame = convertRect(for: tapImageView)
        self.imageView.frame = frameLogic()
    }
}

// MARK: - UIScrollViewDelegate
extension YSGScrollView: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        var centerX = center.x, centerY = center.y
        centerX = scrollView.contentSize.width > scrollView.frame.size.width ? scrollView.contentSize.width / 2 : centerX
        centerY = scrollView.contentSize.height > scrollView.frame.size.height ? scrollView.contentSize.height / 2 : centerY
        imageView.center = CGPoint(x: centerX, y: centerY)
    }
}

// MARK: - CAAnimationDelegate
extension YSGScrollView: CAAnimationDelegate {
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        tapCallback?(imageView)
    }
}
